/**
 * dict.h
 * 接口原型及类型声明。*/

#ifndef DICT_H
#define DICT_H

#include "comm.h"

typedef struct dict      DICT_S;
typedef struct dictItem  DICT_ITEM_S;
typedef struct dictHNode DICT_HNODE_S;

#define DICT_FLAG_FREE  (0x01)
#define DICT_ITEM_EXIST (0x43)

/**
 * 字典条目类型：
 * k 标识；
 * v 值。*/
struct dictItem
{
    COMM_DATA_U k;
    COMM_DATA_U v;
};

/**
 * 字典参数任命类型：
 * khash  key hash 计算回调；
 * kcmp   键值比较回调函数；
 * uext   用户数据，无可置 NULL；
 * irset  字典条目去设置回调函数；
 * malloc 字典虚存分配回调，无可置 NULL；
 * mfree  字典虚存回收回调，无可置 NULL；
 * size_min, 
 * size_max 字典最小/大尺寸；
 * up_nmax  字典内部升级每允许的最大迭代次数；
 * up_tatio 字典条目数/字典hash表大小超过该值时升级。*/
typedef struct dictAppoint
{
    uint64_t (*khash)(const COMM_DATA_U *k);
    int (*kcmp)(const COMM_DATA_U *dk, const COMM_DATA_U *uk);

    void *uext;
    int   (*irset)(DICT_HNODE_S *n, const void *uext);
    void *(*malloc)(size_t s);
    void  (*mfree)(void *ptr);

#define DICT_SIZE_MIN   (11)
#define DICT_RATIO_MIN  (4)
    size_t size_min, size_max;
    size_t up_nmax,  up_ratio;
} DICT_APP_S;

/**
 * 字典 hash 结点类型
 * item 字典条目；
 * next 指向下一结点。*/
struct dictHNode
{
    DICT_ITEM_S   item;
    DICT_HNODE_S *next;
};

/**
 * 字典 hash 表类型：
 * en   hash 表入口；
 * ens  en 数；
 * nds   结点数。*/
typedef struct dictHTbl
{
    DICT_HNODE_S **en;
    size_t ens, nds;
} DICT_HTBL_S;

/**
 * 字典类型：
 * app  字典任命参数；
 * ht   用于字典高效插入和查询的 hash 表；DICT_VERS，发行版和升级版；
 * ui   正升级下标；
 * flag 一些标记；
 * vers 升级次数。*/
struct dict
{
#define DICT_VERS (2)
    DICT_HTBL_S ht[DICT_VERS];
    DICT_APP_S  app;
    size_t ui, flag;
    size_t vers;
};

/**
 * 根据任命参数 app 初始化字典，若参数 d 不为 NULL 则初始化
 * d，返回初始化完成的字典地址。*/
DICT_S * dictAppoint(DICT_S *d, const DICT_APP_S *app);

/**
 * 移除指定字典 d 。
 * 若移除途中有失败 app->irset 
 * 执行失败则返回 irset 相应错误码，
 * 成功返回 COK 。*/
int dictRemove(DICT_S *d);

/**
 * 往字典 d 中添加字典结点 n ，若 n.item.k 标识的字典结点存在则出参
 * exist 值会被置为 DICT_FLAG_EXIST 。
 * 
 * 该函数返回 n.item.k 标识结点的条目值部分地址。
 * 
 * 注：该函数以 DICT_HNODE_S 作为参数是为了让调用者自由组织结点内存，
 * 供其考虑虚存碎片等问题。*/
COMM_DATA_U * dictAdd (DICT_S *d, DICT_HNODE_S *n, int *exist);

/**
 * 在字典 d 中查找 k 标识的条目。
 * 
 * 找到返回该条目值地址，否则返 NULL 。*/
COMM_DATA_U * dictFind(DICT_S *d, const COMM_DATA_U *k);

/**
 * 在字典 d 中删除 k 标识的结点。
 * 
 * 成功返 COK，否则返 irset 中相应错误码。*/
int dictDel(DICT_S *d, const COMM_DATA_U *k);

/**
 * 对字典 d 进行显式升级，每次升级时间不超过
 * up_tmax 纳秒。
 * 
 * 该函数返 CDONE 表明升级完成；返 CING 表明升级
 * 中；返其他值则表明出错。*/
int dictUpgrade(DICT_S *d, uint64_t up_tmax);

#endif